﻿using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

namespace WhiteFlow.DevTrackingTool.UI.Behaviors
{
    /// <summary>
    /// Behavior that helps binding a Command to the Closing event of a window.
    /// </summary>
    public static class WindowClosingToCommandBehavior
    {
        #region Fields

        private static DependencyProperty command;

        #endregion

        #region DependencyProperties Declaration

        /// <summary>
        /// The <see cref="ICommand"/> that will be executed once the owner window will be closing itself.
        /// </summary>
        public static readonly DependencyProperty CommandProperty;

        #endregion

        #region Constructors

        /// <summary>
        /// Static constructor for <see cref="WindowClosingToCommandBehavior"/> class.
        /// </summary>
        static WindowClosingToCommandBehavior()
        {
            #region DependencyProperties Registration

            CommandProperty = DependencyProperty.RegisterAttached(
                "Command",
                typeof(ICommand),
                typeof(WindowClosingToCommandBehavior),
                new FrameworkPropertyMetadata(null, OnCommandChanged));

            #endregion
        }

        #endregion

        #region Getters & Setters

        /// <summary>
        /// Sets the <see cref="ICommand"/> to be executed.
        /// </summary>
        /// <param name="obj">The <see cref="UIElement"/> to which the property is attached.</param>
        /// <param name="value">The value to set.</param>
        public static void SetCommand(UIElement obj, ICommand value)
        {
            obj.SetValue(CommandProperty, value);
        }

        /// <summary>
        /// Gets the <see cref="ICommand"/> to be executed.
        /// </summary>
        /// <param name="obj">The <see cref="UIElement"/> to which the property is attached.</param>
        /// <returns>The command.</returns>
        public static ICommand GetCommand(UIElement obj)
        {
            return obj.GetValue(CommandProperty) as ICommand;
        }

        #endregion

        #region DataBinding Callbacks

        /// <summary>
        /// This callback is called when the binding on the <c>CommandProperty<c/> property has changed.
        /// </summary>
        /// <param name="obj">The <see cref="UIElement"/> to which the property is attached.</param>
        /// <param name="args">The argument of the event.</param>
        private static void OnCommandChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Window window = obj as Window;
            command = args.Property;

            if (window != null)
            {
                if (args.OldValue != null && command != null)
                {
                    window.Closing -= EventHandler;
                }

                if (args.NewValue != null && command != null)
                {
                    window.Closing += EventHandler;
                }
            }
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// The event handler that will be called when the owner window will be closing itself.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The arguments of the event.</param>
        public static void EventHandler(object sender, CancelEventArgs e)
        {
            DependencyObject obj = sender as DependencyObject;

            if (obj != null)
            {
                ICommand cmd = obj.GetValue(command) as ICommand;
                
                if (cmd != null)
                {
                    cmd.Execute(e);
                }
            }
        }

        #endregion
    }
}